package 数据结构OJ;

import java.util.*;

/**
 * @author shy_black
 * @date 2019/8/5 9:32
 * @Description:
 *
 * 运用你所掌握的数据结构，设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作： 获取数据 get 和 写入数据 put 。
 *
 * 获取数据 get(key) - 如果密钥 (key) 存在于缓存中，则获取密钥的值（总是正数），否则返回 -1。
 * 写入数据 put(key, value) - 如果密钥不存在，则写入其数据值。当缓存容量达到上限时，它应该在写入新数据之前删除最近最少使用的数据值，从而为新的数据值留出空间。
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/lru-cache
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 *
 *
 *
 *
 * 使用hashmap加双向链表的形式来解决
 * 首先map存放实际的缓存key与实际数据Node之间的映射
 * Node中存放key与value，组成双向链表
 * 每当有访问key时（get（key）），
 * 1--get（）查看map中是否有key，若有，返回key对应的node中的val，并且将该key对应的node放到链表头部（使用put）
 *
 * 2--若没有，返回-1
 *
 * 3--put（）将key，val包装成一个节点node，查看当前map的size是否大于cap，
 *  若大于 ，则删除链表尾部节点，并删除被删除节点的map的映射，将node放入链表首部，
 *  若还能放下，直接添加到链表首部，
 * 最后在map中添加key-Node映射
 */
public class LRU缓存机制 {


    class LRUCache {


        private LinkedList<Node> list;//存放实际的缓冲value
        private HashMap<Integer, Node> map;//key表示的是缓存的key，Node存放实际的val节点
        private int cap;

        public LRUCache(int capacity) {
            this.cap = capacity;
            map = new HashMap<>();
            list = new LinkedList<>();
        }

        public int get(int key) {
            //当取key时，首先查看list中是否有key对应的Node,不存在，返回-1
            if (!map.containsKey(key)) {
                return -1;
            }
            int val = map.get(key).getVal();
            // 否则就把key对应链表中的val放到链表首部
            //将数据 (key, val) 提到开头
            put(key, val);

            return val;
        }

        public void put(int key, int val) {
            Node node = new Node(key, val);

//        if (key 已存在) {
//        把旧的数据删除；
//        将新节点 x 插入到开头；
//    } else {
//        if (cache 已满) {
//            删除链表的最后一个数据腾位置；
//            删除 map 中映射到该数据的键；
//        }
//        将新节点 x 插入到开头；
//        map 中新建 key 对新节点 x 的映射；
//    }

            if (map.containsKey(key)) {
                //map.put(key,node);
                list.remove(map.get(key));
                list.addFirst(node);

            } else {
                if (map.size() == cap) {
                    int rmKey = list.removeLast().getKey();
                    map.remove(rmKey);
                }
                list.addFirst(node);

            }
            //更新缓存中key-node
            map.put(key, node);

        }
    }

    class Node {
        private int key, val;
        private Node prev, next;


        public Node(int key, int val) {
            this.key = key;
            this.val = val;
        }


        public int getKey() {
            return key;
        }

        public void setKey(int key) {
            this.key = key;
        }

        public int getVal() {
            return val;
        }

        public void setVal(int val) {
            this.val = val;
        }
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */